import json
import os.path
import threading
import time
import glob

import oss2
from aliyunsdkcore import client
from aliyunsdkcore.profile import region_provider
from aliyunsdksts.request.v20150401 import AssumeRoleRequest

from .compBase import TBaseComp
class TPipe:
    def __init__(self):
        self.owner = TCompDataBuffer()
        self.pipeInfo={}
        self.versions={}
        self.threadSave = None
        self.actived = False
        self.db = None
        self.bucketClient = None
        self.stsClient = None
    def getVersionFn(self):
        res=""
        try:
            fnDir = os.path.join( self.pipeInfo['localPath'] , self.pipeInfo['code']);
            if not os.path.exists(fnDir):
                os.makedirs(fnDir,0x777)
            res = os.path.join(fnDir , "version.txt")
        except Exception as er:
            print(er)
        return  res;
    def loadVersions(self):
        try:
            fn = self.getVersionFn()
            if os.path.exists( fn):
                with open(fn ,'r', encoding='utf-8') as f:
                    try:
                        content = f.read()
                        self.versions = json.loads(content)
                    except Exception as eer:
                        print(eer)
                        self.versions={}
            else:
                self.versions={}
        except Exception as er:
            print(er)
    def saveVersions(self):
        try:
            fn = self.getVersionFn()
            content = json.dumps(self.versions)
            with open(fn ,'w', encoding='utf-8') as f :
                f.write(content)
        except Exception as er:
            print(er)
    def saveVersionsLoop(self):
        try:
            if not self.actived:
                self.actived = True
                tm = time.time()
                while self.actived:
                    time.sleep(10)
                    dlt = time.time() - tm
                    if dlt > 60:
                        tm = time.time()
                        self.saveVersions()
        except Exception as er:
            print(er)
    def startAsyncSave(self):
        try:
            self.threadSave = threading.Thread( target=self.saveVersionsLoop , daemon=True)
            self.threadSave.start()
        except Exception as er:
            print(er)
    def setData(self ,  dbPath , queryParam , targetFileName):
        res ={
            "status":0
        }
        try:
            db = self.owner.manager.components['db']
            dbCode = self.pipeInfo['dbCode']
            queryResult = db.queryByKey(dbCode , dbPath , queryParam)
            if queryResult!=None and 'queryStatus' in queryResult.keys() and queryResult['queryStatus'] == 1 :
                content = json.dumps(queryResult)
                fn = os.path.join(self.pipeInfo['localPath'], targetFileName);
                fn = fn + ".txt"
                dirName = os.path.dirname(fn)
                if not os.path.exists(dirName):
                    os.makedirs(dirName, 0x777)
                with open(fn , 'w' , encoding='utf-8') as f :
                    f.write(content)
                tm = time.time()
                version = str(int(tm*1000))
                self.versions[targetFileName] = version
                status , writeRes =  self.upload2oss(targetFileName , content ,  version)
                res['status'] = status
                res['result'] = writeRes
            else:
                res['status'] = -1010
                res['result'] = queryResult
        except Exception as er:
            print(er)
        return  res
    def getDataVersion(self ,  targetFileNameList):
        res ={ }
        try:
            for fn in targetFileNameList:
                if fn in self.versions.keys():
                    res[fn] = self.versions[fn]
                else:
                    res[fn] = 0
        except Exception as er:
            print(er)
        return  res
    def getStsInfo(self ,  roleSessionName,  duration=300):
        res ={
            "status":0,
            "result":{}
        }
        try:
            client = self.getStsClient()
            if client!=None:
                request = AssumeRoleRequest.AssumeRoleRequest()
                sts_role_arn = self.pipeInfo['stsRoleArn']
                request.set_RoleArn(sts_role_arn)
                # 设置会话名称，审计服务使用此名称区分调用者
                request.set_RoleSessionName(roleSessionName)
                request.set_DurationSeconds(duration)
                # 发起请求，并得到response
                response = client.do_action_with_exception(request)
                result = json.loads(oss2.to_unicode(response))
                print(result)
                res['result'] = result
                res['option'] ={
                    "region":self.pipeInfo['uploadEndpoint'] ,
                    "authorizationV4":True,
                    "accessKeyId": result['Credentials']['AccessKeyId'],
                    "accessKeySecret": result['Credentials']['AccessKeySecret'],
                    "stsToken":result['Credentials']['SecurityToken'],
                    "bucket": self.pipeInfo['bucket']
                }
                res['status'] = 1
        except Exception as er:
            print(er)
        return  res
    def getBucketClient(self):
        res = None
        try:
            if self.bucketClient == None:
                access_key_id = self.pipeInfo['ak']
                access_key_secret = self.pipeInfo['sk']
                endpoint = self.pipeInfo['endpoint']
                bucketName = self.pipeInfo['bucket']
                try:
                    res = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucketName)
                    self.bucketClient = res
                except Exception as ee:
                    res = None
                    print(ee)
            else:
                res = self.bucketClient
        except Exception as er :
            print(er)
        return res
    def getStsClient(self):
        res = None
        try:
            if self.stsClient == None :
                access_key_id = self.pipeInfo['ak']
                access_key_secret = self.pipeInfo['sk']
                endpoint = self.pipeInfo['shortEndpoint']
                try:
                    res = client.AcsClient(access_key_id, access_key_secret, endpoint)
                    self.stsClient = res
                except Exception as ee:
                    res = None
                    print(ee)
            else:
                res = self.stsClient
        except Exception as er :
            print(er)
        return  res
    def upload2oss(self , targetFn , content , version):
        status = 0
        res = {
            "dataUrl":"",
            "versionUrl":""
        }
        try:
            dataFn = targetFn+".txt"
            versionFn = targetFn+"_ver.txt"
            bucket = self.getBucketClient()
            if bucket!=None:
                result = bucket.put_object(dataFn, content)
                if result.status==200:
                    endpoint = self.pipeInfo['endpoint']
                    bucketName = self.pipeInfo['bucket']
                    res['dataUrl'] = 'http://' + bucketName + '.' + endpoint + "/" + dataFn
                    bucket.put_object(versionFn, str(version))
                    res['versionUrl'] = 'http://' + bucketName + '.' + endpoint + "/" + versionFn
                    res['version'] = version
                    status = 1
                else:
                    status = result.status
            else:
                res['status'] = -1020
        except Exception as er:
            print(er)
        return  status , res

    def getDataPath(self):
        res ={}
        try:
            fs =[]
            dbCode = self.pipeInfo['dbCode']
            dbComp = self.owner.manager.components['db']
            res = dbComp.getSqlList(dbCode)
        except Exception as er:
            print(er)
        return res
class TCompDataBuffer(TBaseComp):
    def __init__(self):
        super().__init__()
        self.componentKey = 'dataBuffer'
        self.pipes = {}
        self.handlers={
            "setData":self.setData,
            "getDataVersion": self.getDataVersion,
            "getStsInfo": self.getStsInfo,
            "getDataPath": self.getDataPath
        }
    def setData(self , code , dbPath , queryParam , targetFn):
        res ={
            "status":0
        }
        try:
            pipe , status  = self.getPipe(code)
            if status==1 :
                res = pipe.setData(dbPath , queryParam , targetFn)
            else:
                res['status'] = status
        except Exception as er:
            print(er)
        return  res
    def getDataVersion(self , code , fnList):
        res ={
            "status":0
        }
        try:
            pipe , status  = self.getPipe(code)
            if status==1 :
                res = {
                    "status":1,
                    "result":pipe.getDataVersion(fnList)
                }
            else:
                res['status'] = status
        except Exception as er:
            print(er)
        return  res
    def getStsInfo(self , code , roleSessionName,  duration=3000):
        res ={
            "status":0
        }
        try:
            pipe , status  = self.getPipe(code)
            if status==1 :
                res = pipe.getStsInfo(roleSessionName,  duration)
            else:
                res['status'] = status
        except Exception as er:
            print(er)
        return  res
    def getDataPath(self , code ):
        res ={
            "status":0
        }
        try:
            pipe , status  = self.getPipe(code)
            if status==1 :
                res['result'] = pipe.getDataPath()
                res['status'] = 1
            else:
                res['status'] = status
        except Exception as er:
            print(er)
        return  res

    def getPipe(self, code):
        res = None
        status = 0
        try:
            if code in self.pipes.keys():
                res = self.pipes[code]
                status = 1
            else:
                if code in self.settings.keys():
                    pipe = TPipe()
                    pipe.owner = self
                    pipe.pipeInfo = self.settings[code]
                    pipe.loadVersions()
                    self.pipes[code] = pipe
                    pipe.startAsyncSave()
                    res = pipe
                    status = 1
                else:
                    status = -1000

        except Exception as er:
            print(er)
        return  res , status


compDataBuffer = TCompDataBuffer()
compDataBuffer.regist()